#ifndef SWE_COMMON_H
#define SWE_COMMON_H

#ifdef WIN32
#define SWEGL_WINDOWS 1
#include <windows.h>
#else
#define SWEGL_LINUX 1
#endif

// for size_t
#include <cstring>

#if SWEGL_WINDOWS
typedef int     sint;
typedef __int8  sint8;
typedef __int16 sint16;
typedef __int32 sint32;
typedef __int64 sint64;

typedef unsigned int uint;
typedef unsigned __int8  uint8;
typedef unsigned __int16 uint16;
typedef unsigned __int32 uint32;
typedef unsigned __int64 uint64;

#define SWEGL_FUNCTION __FUNCSIG__
#define swegl_attribute(x)

#define SWEGL_MULTI_LINE_MACRO_BEGIN do {  
#define SWEGL_MULTI_LINE_MACRO_END \
    __pragma(warning(push)) \
    __pragma(warning(disable:4127)) \
    } while(0) \
    __pragma(warning(pop))  

// C99 printf format
#define __STDC_FORMAT_MACROS
#include "inttypes.h"

#endif

#if SWEGL_LINUX
#include <stdint.h>

typedef int     sint;
typedef int8_t  sint8;
typedef int16_t sint16;
typedef int32_t sint32;
typedef int64_t sint64;

typedef unsigned int uint;
typedef uint8_t  uint8;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;

#define SWEGL_FUNCTION __PRETTY_FUNCTION__
#define swegl_attribute(x) __attribute__(x)

#define SWEGL_MULTI_LINE_MACRO_BEGIN do {  
#define SWEGL_MULTI_LINE_MACRO_END } while (0)

// C99 printf format
#define __STDC_FORMAT_MACROS
#include <inttypes.h>

#endif

// string concatenation
#define SWEGL_JOIN2(a, b) a ## b
#define SWEGL_JOIN(a, b) SWEGL_JOIN2(a, b)

// get the number of element of an array
#define COUNT_OF(t) (sizeof(t) / sizeof(t[0]))

// stdargs
#include <stdarg.h>

namespace swegl
{
namespace Log
{
	void Warning(const char *str, ...);
	void Info(const char *str, ...);
}
}

#define sweglWarning(fmt,...) \
	SWEGL_MULTI_LINE_MACRO_BEGIN \
	swegl::Log::Warning(fmt, ##__VA_ARGS__); \
	SWEGL_MULTI_LINE_MACRO_END

#define sweglInfo(fmt,...) \
	SWEGL_MULTI_LINE_MACRO_BEGIN \
	swegl::Log::Info(fmt, ##__VA_ARGS__); \
	SWEGL_MULTI_LINE_MACRO_END

namespace swegl
{
namespace Assert
{
	void AssertionFailed(char const *expr, char const *function, char const *file, long line) swegl_attribute((noreturn));
	void AssertionFailed(char const *expr, char const *function, char const *file, long line, const char *fmt, ...) swegl_attribute((noreturn)) swegl_attribute((format (printf, 5, 6)));
}
}

// runtime assertion
#define sweglAssert(expr) \
	SWEGL_MULTI_LINE_MACRO_BEGIN \
	((expr) ? ((void)0): swegl::Assert::AssertionFailed(#expr, SWEGL_FUNCTION, __FILE__, __LINE__)); \
	SWEGL_MULTI_LINE_MACRO_END

// assertion with custom message
#define sweglAssertMsg(expr, ...) \
	SWEGL_MULTI_LINE_MACRO_BEGIN \
	((expr) ? ((void)0): swegl::Assert::AssertionFailed(#expr, SWEGL_FUNCTION, __FILE__, __LINE__, ##__VA_ARGS__)); \
	SWEGL_MULTI_LINE_MACRO_END

// compile time assertion
#define sweglStaticAssert(cond) typedef int SWEGL_JOIN(static_assert_dummy_typedef_, __LINE__)[(cond) ? 1 : -1]

#endif
